<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // 函数式编程： 编程范式  js多范式语言。
    // 函数js一等公民 ，给函数式提供天然优势。
    // 函数式编程：强调以函数使用为主的软件开发风格 ，也是一种范式。

    // 源于数学；
    // y = f(x);   纯函数。 
    // 纯函数是对给定的输入返还相同输出的函数 （不可变性）;

    // 一、纯函数。
    // 不是一个纯函数
    // let factor = 2;
    // const total = function(num){
    //     return num * factor;
    // }
    // total(1);

    // 是纯函数
    // const total = function(num){
    //     return num * 2;
    // }
    // total(1);

    // 纯函数的意义
    // 无副作用 ：可移植性；
    // 可读性强 
    // 可测性
    // test("total(2) 等于 4" ,()=>{
    //     expect(total(2)).toBe(4);
    // })
    // 可以为组合成更复杂功能提供可能性。


    // 二、声明式 和 命令式。
    // 1.声明式（抽象：复用性）强调“做什么?”  2.命令式 强调“怎么做？？”
    // let arr = ["张三","李四","王五"];
    // 命令式 
    // for(let i=0;i<arr.length;i++){
    //     console.log(arr[i]);
    // }

    // 声明式 ：抽象循环过程。 map every reduce filter some ...
    // const forEach = function(arr,fn){
    //     for(let i=0;i<arr.length;i++){
    //         fn(arr[i]);
    //     }
    // }
    // forEach(arr,function(item){
    //     console.log(item);
    // })

    // 三、高阶函数：以函数作为输入或者输出的函数被称为高阶函数(Higher-Order Function)
    // 函数作为输入
    // function test(cb){
    //     cb && cb();
    // }
    // 函数作为输出。
    // function test(){
    //     let a = 10;
    //     return function(){
    //         console.log(a);
    //     }
    // }
    // test()();
    // 意义：1.缓存特性 2.惰性执行
    // const once = function(fn){
    //     let done = false;
    //     return function(){
    //         if(!done){
    //             fn();
    //             done = true;
    //         }else{
    //             console.log("已经执行过了");
    //         }
    //     }
    // }
    // // 让test 只执行一次；
    // function test(){
    //     console.log("test");
    // }
    // let myfn = once(test);
    // myfn();
    // myfn();
    // myfn();
    // myfn();

    // 四、柯里化 curry ：柯里化是把一个多参数函数转化成一个嵌套的一元函数的过程；

    // 实现 add(1)(2)(3)??
    // function add(x,y,z,o){
    //     return x + y + z +o;
    // }
    // console.log(add.length);

    // 简版的curry 
    // const curry = function(fn){
    //     return function(x){
    //         return function(y){
    //             return function(z){
    //                 return fn(x,y,z);
    //             }
    //         }
    //     }
    // }

    // 通用的curry x -->x,y ---> x,y,z ....递归
    // const curry = function (fn) {
    //     return function curryFn(...args) {
    //         if (args.length < fn.length) {
    //             return function () {
    //                 return curryFn(...args, ...arguments);
    //             }
    //         } else {
    //             return fn(...args);
    //         }
    //     }
    // }


    // let myAdd = curry(add);
    // let res =  myAdd(1)(2)(3)(4);
    // console.log(res);

    // 柯里化意义
    // 1.参数复用
    // let str1 = 'abcd';
    // let str2 = 'efgh';
    // let str = "fg--"
    // function addStr(str1,str2){
    //     return str1 + str2;
    // }

    // // console.log(addStr(str,str1));
    // // console.log(addStr(str,str2));
    // // curry 参数复用
    // let curryFn =  curry(addStr);
    // // str参数复用
    // let myfn =  curryFn(str);
    // console.log( myfn(str1));
    // console.log( myfn(str2));

    // 2、惰性执行；
    // function getAjax(method,action){
    //     let xhr;
    //     if(XMLHttpRequest){
    //         return function(){
    //             xhr = new XMLHttpRequest();
    //             // ....
    //             // xhr.open(method,)... onload 
    //         }
    //     }else{
    //         return function(){
    //             xhr = new ActiveXObject();
    //             // ....
    //         }
    //     }
    //     // return xhr;
    // }
    // // 柯里化
    // let http = getAjax("get");
    // http("/api/getUsers");
    // 3.只能接受一个参数 
    // js柯里化  bind函数 bind(this)(1);

    // 组合函数 ： Pointfree  编程风格
    // 获取句号 统计长度 判断奇偶
    // let str = "大家好。我是中国人,我爱中国。";

    // function getOddOrEven(str) {
    //     let res = str.match(/。/g);
    //     let result = res.length % 2 === 0 ? '偶数' : '奇数';
    //     return result
    // }

    // console.log( getOddOrEven(str));
    // 1.获取句号
    // const getPeriod = str=>str.match(/。/g);
    // 2.统计长度
    // const getLength = str=>str.length;
    // 3.判断奇偶
    // const oddOrEven = num=>num%2===0?'偶数':'奇数';

    // compose   : 从右至左组合 把运算过程组合起来。
    // 简版的
    // const compose = function(oddOrEven,getLength,getPeriod){
    //     return function(str){
    //         return  oddOrEven(getLength(getPeriod(str)));
    //     }
    // }

    // 通用版的compose:从右至左组合
    // const compose  = function(...fns){
    //     return function (arg){
    //         return fns.reverse().reduce((acc,fn)=>{
    //             return fn(acc);
    //         },arg);
    //     }
    // }
    // pipe 管道 从左至右组合
    // const pipe  = function(...fns){
    //     return function (arg){
    //         return fns.reduce((acc,fn)=>{
    //             return fn(acc);
    //         },arg);
    //     }
    // }

    // 组合运算过程
    // let getResFn =compose(oddOrEven,getLength,getPeriod) ; 
    // 基于str执行结果
    // console.log(getResFn(str));
    // koa 中间件执行  koa-compose


    // 作业：通过声明式编程方式 实现 filter 及 map 达到原生的效果。
    let arr = ["张三","李四","王五"];

//     const filter = function(arr,fn){
//         let res = []
//         for(let i=0;i<arr.length;i++){
//             if(fn(arr[i])){
//                 res.push(arr[i])
//             }
//         }
//         return res
//     }

    
//    let res = filter(arr,function(item){
//           return typeof item === 'string'
//     })
//     console.log(res)

const map = function(arr,fn){
        let res = []
        for(let i=0;i<arr.length;i++){
            res.push(fn(arr[i]))
        }
        return res
    }

    
   let res = map(arr,function(item){
          return item + '属于羽毛球队'
    })
    console.log(res)
</script>

</html>